# Description: DNS Black List middleware
# Author: Wijnand 'tehmaze' Modderman
# License: LGPL

from django.http import HttpResponseForbidden
import socket

__version__ = '$Id: middleware.py 2 2007-07-08 19:28:39Z tehmaze $'

try:
    import DNS
    # automatically load nameserver(s) from /etc/resolv.conf
    # (works on unix - on others, YMMV)
    DNS.ParseResolvConf()
except ImportError:
    DNS = None

class DNSBLMiddleware(object):
    # define your DNSBL's in here, for a nice overview, check out
    # `http://www.moensted.dk/spam/`_
    DNSBL = (
        'sbl.spamhaus.org',
        'http.dnsbl.sorbs.net',
        'socks.dnsbl.sorbs.net',
        'misc.dnsbl.sorbs.net',
        'escalations.dnsbl.sorbs.net',
        )

    def process_request(self, request):
        '''
        Check the `REMOTE_ADDR` against the blacklists defined in `DNSBLMiddleware.DNSBL`. If
        we have a positive match, reject the request using `DNSBLMiddleware.reject_request()`.
        '''
        if request.META.has_key('REMOTE_ADDR'):
            ip = request.META['REMOTE_ADDR']
            octets = ip.split('.')
            octets.reverse()
            ip = '.'.join(octets)
            for blacklist in self.DNSBL:
                test = '%s.%s' % (ip, blacklist)
                try:
                    lookup = socket.gethostbyname(test)
                except socket.error:
                    lookup = ''
                if lookup.startswith('127.0.0.'):
                    return self.reject_request(request, test)
        return None

    def reject_request(self, request, via):
        '''
        Reject the request, try to use the `DNS` module to look up the TXT record to give a
        more friendly message to the visitors that are blocked. If all fails, fall back using
        a message.
        '''
        if DNS:
            # lets do an all-in-one request
            # set up the request object
            r = DNS.DnsRequest(name=via,qtype='TXT')
            # do the request
            a=r.req()
            if a.header['status'] != 'NOERROR':
                return HttpResponseForbidden('You are listed in %s, access denied' % via)
            try:
                reason = a.answers[0]['data'][0]
                return HttpResponseForbidden('You are listed in %s: %s' % (via, reason))
            except KeyError:
                pass
            except IndexError:  
                pass 
        return HttpResponseForbidden('You are listed in %s, access denied' % via)

# test suite
if __name__ == '__main__':
    m = DNSBLMiddleware()
    class request:
        META = {'REMOTE_ADDR': '201.58.1.144'}
    print m.process_request(request())
